// LemCoop
// Copyright (C) 2013  Oliver Naumann <bldrax@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "gameengine.h"

GameEngine::GameEngine()
{
	m_state = nullptr;
	m_next_state = nullptr;

	m_end_game = false;

	m_timing_factor_timer = al_create_timer(0.000001f);

	// Initialize the input event queue.
	m_input_queue = al_create_event_queue();
	// TODO: Error handling.
	al_register_event_source(m_input_queue, al_get_mouse_event_source());
	al_register_event_source(m_input_queue, al_get_keyboard_event_source());

	// Create the top layer bitmap. It is as large as the screen.
	m_top_layer = al_create_bitmap( Screen::GetInstance()->width(), Screen::GetInstance()->height());

	//DEBUG
	m_fps_font = al_load_font(STANDARD_FONT.c_str(), STANDARD_FONT_SIZE, NULL);
}

GameEngine::~GameEngine()
{
	delete m_state;

	// Automatically unregisters the event sources too.
	al_destroy_event_queue(m_input_queue);
}

void GameEngine::ChangeGameState()
{
	delete m_state;
	m_state = m_next_state;
	m_next_state = nullptr;
}

void GameEngine::SetNextState(GameState* new_state)
{
	m_next_state = new_state;
}

void GameEngine::CheckState()
{
	if (m_next_state != nullptr)
		ChangeGameState();
}

void GameEngine::HandleInput()
{
	ALLEGRO_EVENT next_event;

	while (al_get_next_event(m_input_queue, &next_event))
	{
		m_state->HandleInput(next_event);
	}
}

void GameEngine::Update()
{
	m_timing_factor = 1.0f;
	if (!al_get_timer_started(m_timing_factor_timer))
	{
		al_start_timer(m_timing_factor_timer);
		m_timing_factor = 1.0f;
	}
	else
	{
		m_timing_factor = al_get_timer_count(m_timing_factor_timer) / 1000.0f;
		al_set_timer_count(m_timing_factor_timer, 0);
	}

	m_state->Update(m_timing_factor);
}

void GameEngine::Draw()
{
	// Clear the top layer.
	al_set_target_bitmap(m_top_layer);
	al_clear_to_color(al_map_rgba(0, 0, 0, 0));

	// Clear the backbuffer and draw everything.
	al_set_target_bitmap(al_get_backbuffer(System::GetInstance()->display()));
	al_clear_to_color(al_map_rgb(0, 0, 0));
	m_state->Draw();

	// Draw the top layer (high priority graphics).
	al_draw_bitmap(m_top_layer, 0, 0, NULL);

	//DEBUG
	al_draw_textf(m_fps_font, al_map_rgb(255,255,255), 1014, 10, ALLEGRO_ALIGN_RIGHT, "FPS: %d", (int)(1000.0f / m_timing_factor));

	// Show the image.
	al_flip_display();
}